import UIKit

extension String {
    
    subscript (i: Int) -> Character {
        return self[index(startIndex, offsetBy: i)]
    }
    
    subscript (i: Int) -> String {
        return String(self[i] as Character)
    }
    
    subscript (r: Range<Int>) -> String {
        let start = index(startIndex, offsetBy: r.lowerBound)
        let end = index(startIndex, offsetBy: r.upperBound)
        return String(self[start ..< end])
    }
    
    var containsAlphabets: Bool {
        //Checks if all the characters inside the string are alphabets
        let set = CharacterSet.letters
        return self.utf16.contains {
            guard let unicode = UnicodeScalar($0) else { return false }
            return set.contains(unicode)
        }
    }
    
    /**
     计算文字的宽度
     
     - parameter font:
     - parameter size:
     
     - returns:
     */
   func getWidth(fontSize: CGFloat, height: CGFloat = 15) -> CGFloat {
        let font = UIFont.systemFont(ofSize: fontSize)
        let rect = NSString(string: self).boundingRect(with: CGSize(width: CGFloat(MAXFLOAT), height: height), options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: font], context: nil)
        return ceil(rect.width)
    }
    
    func getHeight(font:UIFont, width:CGFloat ,maxHeight:CGFloat = CGFloat(MAXFLOAT)) -> CGFloat
    {
        let rect = NSString(string: self).boundingRect(with: CGSize(width: width, height: maxHeight), options: .usesLineFragmentOrigin, attributes: [.font:font], context: nil)
        return ceil(rect.height)
    }
    
    // MARK:手机号（国内）
    static func isChinaPhoneLegal(phoneNo: String, areaCode: String = "+86") -> Bool {
        if areaCode != "+86" {
            return false
        }
        let regex = "^[0-9]{11}$"
        if NSPredicate(format: "SELF MATCHES %@", regex).evaluate(with: phoneNo) {
            return true
        }
        return false
    }
    
    // MARK: CAST TO OTHER TYPE API
    
    /// 转double
    ///
    /// - Parameters:
    ///   - def: 默认值
    ///   - decimal: 舍弃小数位精度
    /// - Returns:
    func toDouble(_ def: Double = 0.0, decimal: Int? = nil) -> Double {
        if !self.isEmpty {
            var doubleValue = Double(self) ?? def
            if let dec = decimal {
                doubleValue = doubleValue.f(places: dec)
            }
            return doubleValue
        } else {
            return def
        }
    }
    
    func toUnitDouble(_ def: Double = 0.0, decimal: Int? = nil, unitKey:[String], unitValue: Int) -> Double{
        if !self.isEmpty {
            for (i, key) in unitKey.enumerated(){
                if self.contains(key) {
                    if let baseDoubleStr = self.components(separatedBy: key).first{
                        if let baseDouble = Double(baseDoubleStr) {
                            var finalDouble = (Decimal(baseDouble) * pow(Decimal(unitValue), i) as NSDecimalNumber).doubleValue
                            if let dec = decimal {
                                finalDouble = finalDouble.f(places: dec)
                            }
                            return finalDouble
                        }
                    }
                    
                }
            }
            return self.toDouble(def, decimal: decimal)
        } else {
            return def
        }
    }
    
    func toFloat(_ def: Float = 0.0) -> Float {
        if !self.isEmpty {
            return Float(self) ?? def
        } else {
            return def
        }
    }
    
    func toInt(_ def: Int = 0) -> Int {
        if !self.isEmpty {
            return Int(self)!
        } else {
            return def
        }
    }
    
    func toBool(_ def: Bool = false) -> Bool {
        if !self.isEmpty {
            let value = Int(self)!
            if value > 0 {
                return true
            } else {
                return false
            }
        } else {
            return def
        }
    }
    
    func ranges(of string: String) -> [Range<String.Index>] {
        var rangeArray = [Range<String.Index>]()
        var searchedRange: Range<String.Index>
        guard let sr = self.range(of: self) else {
            return rangeArray
        }
        searchedRange = sr
        
        var resultRange = self.range(of: string, options: .regularExpression, range: searchedRange, locale: nil)
        while let range = resultRange {
            rangeArray.append(range)
            searchedRange = Range(uncheckedBounds: (range.upperBound, searchedRange.upperBound))
            resultRange = self.range(of: string, options: .regularExpression, range: searchedRange, locale: nil)
        }
        return rangeArray
    }
}

// MARK: - NSAttributedString extensions
public extension String {
    
    /// Regular string.
     var regular: NSAttributedString {
        return NSMutableAttributedString(string: self, attributes: [.font: UIFont.systemFont(ofSize: UIFont.systemFontSize)])
    }
    
    /// Bold string.
     var bold: NSAttributedString {
        return NSMutableAttributedString(string: self, attributes: [.font: UIFont.boldSystemFont(ofSize: UIFont.systemFontSize)])
    }
    
    /// Underlined string
     var underline: NSAttributedString {
        return NSAttributedString(string: self, attributes: [.underlineStyle: NSUnderlineStyle.single.rawValue])
    }
    
    /// Strikethrough string.
     var strikethrough: NSAttributedString {
        return NSAttributedString(string: self, attributes: [.strikethroughStyle: NSNumber(value: NSUnderlineStyle.single.rawValue as Int)])
    }
    
    /// Italic string.
     var italic: NSAttributedString {
        return NSMutableAttributedString(string: self, attributes: [.font: UIFont.italicSystemFont(ofSize: UIFont.systemFontSize)])
    }
    
    /// Add color to string.
    ///
    /// - Parameter color: text color.
    /// - Returns: a NSAttributedString versions of string colored with given color.
     func colored(with color: UIColor) -> NSAttributedString {
        return NSMutableAttributedString(string: self, attributes: [.foregroundColor: color])
    }
}

extension Array where Element: NSAttributedString {
    func joined(separator: NSAttributedString) -> NSAttributedString {
        var isFirst = true
        return self.reduce(NSMutableAttributedString()) {
            (r, e) in
            if isFirst {
                isFirst = false
            } else {
                r.append(separator)
            }
            r.append(e)
            return r
        }
    }
    
    func joined(separator: String) -> NSAttributedString {
        return joined(separator: NSAttributedString(string: separator))
    }
}
